package com.htsk.city.services.wechat.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.htsk.city.services.core.dao.*;
import com.htsk.city.services.core.domain.*;
import com.htsk.city.services.core.entity.ObjectTrans;
import com.htsk.city.services.core.entity.PageInfo;
import com.htsk.city.services.core.entity.R;
import com.htsk.city.services.core.utils.GeoUtils;
import com.htsk.city.services.wechat.params.*;
import com.htsk.city.services.wechat.vo.CommentVO;
import com.htsk.city.services.wechat.vo.PostVO;
import com.htsk.city.services.wechat.vo.UserInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 圈子服务
 */
@Service
@Slf4j
public class PostService {

    @Resource
    private TopicDao topicDao;
    @Resource
    private PostDao postDao;
    @Resource
    private PostTopicDao  postTopicDao;
    @Resource
    private LikesDao  likesDao;
    @Resource
    private CommentDao commentDao;
    @Resource
    private MentionDao mentionDao;
    @Resource
    private CommentLikeDao commentLikeDao;
    @Resource
    private UserService userService;

    public R<List<Topic>> listTopic(){
        return R.ok(topicDao.findAllByStatusAndDelFlag(1,0));
    }

    @Transactional
    public R<Long> publishPost(WxUser wxUser,PublishPostsParam publishPostsParam){
        Post post = publishPostsParam.trans(wxUser);
        postDao.save(post);

        List<PostTopic> postTopicList=new ArrayList<>();
        for (Long topicId : publishPostsParam.getTopicIds()) {
            PostTopic postTopic = new PostTopic();
            postTopic.setTopicId(topicId);
            postTopic.setCreatedAt(post.getCreatedAt());
            postTopic.setPostId(post.getId());
            postTopicList.add(postTopic);

        }

        postTopicDao.saveAll(postTopicList);
        return R.ok(post.getId());
    }

    public R<Long> delPost(WxUser wxUser,Long postId){
        Post post= postDao.findByIdAndUserId(postId,wxUser.getId());
        if (post!=null){
            post.setDelFlag(1);
            postDao.save(post);
        }
        return R.ok(postId);
    }

    public R<PageInfo<PostVO,Post>> pagePost(PostQueryParam pageQueryParam){
        WxUser wxUser = null;
        try {
            wxUser= JSONUtil.toBean((String) StpUtil.getLoginId(),WxUser.class);
        }catch (Exception ignored){

        }
        Page<Post> postPage=postDao.findByDelFlag(0,pageQueryParam.getPageable());
        WxUser finalWxUser = wxUser;
        ObjectTrans<PostVO,Post> trans= j->getPostVO(j,finalWxUser,pageQueryParam.getLatitude().doubleValue(),pageQueryParam.getLongitude().doubleValue(),true);
        return R.ok(new PageInfo<>(pageQueryParam.getPageable(),postPage,trans));
    }

    public R<PageInfo<PostVO,Post>> pageMyPost(WxUser wxUser,PostQueryParam pageQueryParam){
        Page<Post> postPage=postDao.findByUserIdAndDelFlag(wxUser.getId(), 0,pageQueryParam.getPageable());
        ObjectTrans<PostVO,Post> trans= j->getPostVO(j, wxUser,pageQueryParam.getLatitude().doubleValue(),pageQueryParam.getLongitude().doubleValue(),true);
        return R.ok(new PageInfo<>(pageQueryParam.getPageable(),postPage,trans));
    }

    public PostVO getPostVO(Post j,WxUser wxUser,double longitude,double latitude,boolean calcD){
        List<PostTopic> postTopicList=postTopicDao.findByPostId(j.getId());
        List<Long> topicIds= postTopicList.stream().map(PostTopic::getTopicId).collect(Collectors.toList());
        List<Topic> topicList=topicDao.findAllByIdIn(topicIds);

        UserInfoVO userInfoVO=userService.getUserInfo(j.getUserId());
        double d= GeoUtils.calculateDistance(j.getLatitude().doubleValue(),j.getLongitude().doubleValue(),latitude,longitude);
        Likes likes=null;
        if (wxUser !=null){
            likes=likesDao.findByPostIdAndUserId(j.getId(),wxUser.getId());
        }
        return new PostVO(j,userInfoVO,topicList, BigDecimal.valueOf(calcD ? d : -1D),likes!=null);
    }
    @Transactional
    public R<PostVO> likePost(WxUser wxUser,Long postId){
        Post post=postDao.findById(postId).orElse(null);

        if (post!=null&&post.getDelFlag() != 1){
            Likes likes=likesDao.findByPostIdAndUserId(postId,wxUser.getId());
            if (likes!=null){
                likesDao.delete(likes);
                post.setLikeCount(post.getLikeCount()-1);
            }else{
                likes=new Likes();
                likes.setPostId(postId);
                likes.setUserId(wxUser.getId());
                likes.setCreatedAt(DateUtil.date());
                likesDao.save(likes);
                post.setLikeCount(post.getLikeCount()+1);
            }
            postDao.save(post);
            return R.ok(getPostVO(post,wxUser,0D,0D,false));
        }
        return R.fail("帖子不存在");

    }

    @Transactional
    public R<Long> publishCommment(WxUser wxUser, PublishCommmentParam publishCommmentParam){
        Comment comment=publishCommmentParam.getComment(wxUser);
        commentDao.save(comment);
        Post post=postDao.findById(publishCommmentParam.getPostId()).orElse(null);
        if (post!=null){
            post.setCommentCount(post.getCommentCount()+1);
            postDao.save(post);
        }
        return R.ok(comment.getId());
    }

    public R<PageInfo<CommentVO,Comment>> queryComment(CommentQueryParam commentQueryParam){
        WxUser wxUser = null;
        try {
            wxUser= JSONUtil.toBean((String) StpUtil.getLoginId(),WxUser.class);
        }catch (Exception ignored){

        }
        WxUser finalWxUser = wxUser;
        Page<Comment> commentPage=commentDao.findByPostIdAndParentIdAndDelFlag(commentQueryParam.getPostId(),0L,0,commentQueryParam.getPageable());
        ObjectTrans<CommentVO,Comment> trans=c->getCommentVO(c,finalWxUser);
        return R.ok(new PageInfo<>(commentPage.getPageable(),commentPage,trans));
    }

    private CommentVO getCommentVO(Comment c,WxUser finalWxUser){
        List<Comment> children=commentDao.findByPostIdAndParentIdAndDelFlag(c.getPostId(),c.getId(),0);
        List<CommentVO> childrenVOs=children.stream().map(e->{
            UserInfoVO userInfo=userService.getUserInfo(e.getUserId());
            UserInfoVO replyToUser=null;
            if (e.getReplyToUserId()!=null){
                replyToUser=userService.getUserInfo(e.getReplyToUserId());
            }
            return new CommentVO(e,userInfo,replyToUser,null,false);
        }).collect(Collectors.toList());
        UserInfoVO userInfo=userService.getUserInfo(c.getUserId());
        UserInfoVO replyToUser=null;
        if (c.getReplyToUserId()!=null){
            replyToUser=userService.getUserInfo(c.getReplyToUserId());
        }
        CommentLike likes=null;
        if (finalWxUser !=null){
            likes=commentLikeDao.findByCommentIdAndUserId(c.getId(),finalWxUser.getId());
        }
        return new CommentVO(c,userInfo,replyToUser,childrenVOs,likes!=null);
    }
    @Transactional
    public R<CommentVO> likeComment(WxUser wxUser,Long commentId){
        Comment comment=commentDao.findById(commentId).orElse(null);

        if (comment!=null&&comment.getDelFlag() != 1){
            CommentLike likes=commentLikeDao.findByCommentIdAndUserId(comment.getId(),wxUser.getId());
            if (likes!=null){
                commentLikeDao.delete(likes);
                comment.setLikeCount(comment.getLikeCount()-1);
            }else{
                likes=new CommentLike();
                likes.setCommentId(commentId);
                likes.setUserId(wxUser.getId());
                likes.setCreatedAt(DateUtil.date());
                commentLikeDao.save(likes);
                comment.setLikeCount(comment.getLikeCount()+1);
            }
            commentDao.save(comment);
            return R.ok(getCommentVO(comment,wxUser));
        }
        return R.fail("评论不存在");
    }

    public R<Boolean> readPost(List<Long> postIds){
        List<Post> postList=postDao.findByIdInAndDelFlag(postIds,0);
        for (Post post : postList) {
            post.setBrowseCount(post.getBrowseCount()+1);
        }
        postDao.saveAll(postList);
        return R.ok(true);
    }

    public R<Long> delComment(WxUser wxUser,Long commentId){
        Comment post= commentDao.findByUserIdAndId(wxUser.getId(),commentId);
        if (post!=null){
            post.setDelFlag(1);
            commentDao.save(post);
        }
        return R.ok(commentId);
    }
}
